function Swipe(container, options) {
  if (!container) return;
  var offloadFn = function(fn) { setTimeout(fn || function() {}, 0) }; 
  // 检查浏览器兼容
  var browser = {
    addEventListener: !!window.addEventListener,
    touch: ('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch,
    transitions: (function(temp) {
      var props = ['transitionProperty', 'WebkitTransition', 'MozTransition', 'OTransition', 'msTransition'];
      for ( var i in props ) if (temp.style[ props[i] ] !== undefined) return true;
      return false;
    })(document.createElement('div'))
  };

  var _opts = {// 配置选项
	    "width":0,
		"height":0,
		"startSlide":0,// 开始下标
		"speed":1000,//滑动速度
		"continuous":true,//是否循环
		"slideEnd":function(inx,count,slide){},// 滑动结束
		"dotsElement":null,// 滑动标识区域对象
		"delay":2500, //延时滑动时间
		"stopPropagation":false, //阻止事件冒泡
		"disableScroll":false,// 阻止滚动
		"auto":true, // 是否自动播放
        "fixHeight":true,//固定高度
        "fixWidth":true,// 固定宽度
		"showDot":true, // 显示小圆点
		"showOrgImg":false // 显示原图 
  };
  for(var key in options){
	_opts[key] = options[key];
  }
  // 全局对象
  var _gv = {
	"index":_opts.startSlide,// 当前滑动下标
	"slideInterval":null, //自动播放定时器 
	"evtStart":{},// 触摸开始数据记录对象
	"evtDelta":{},// 触摸滑动时数据记录对象
	"isScrolling":false, // 是否滚动 
	"slideEles":container.children[0].children,// 滑动元素
	"slidePos":[],// 滑动位置
    "slideWidth":0,// 滑动块宽度
	"slideHeight":0,// 滑动块高度
	"slideCount":container.children[0].children.length,// 滑动块数量
	"dotsElement":null, // 小圆点元素对象
	"swipeWrap":container.children[0] // 滑动容器

  }
  // 启动
  function setup() {
    // cache slideEles
    if(_opts.showDot && _opts.dotsElement){
        createDots(_opts.startSlide);
    }
    // set continuous to false if only one slide
    if (_gv.slideCount < 2){
		_opts.continuous = false;
	}
    // determine slideWidth of each slide
    _gv.slideWidth = $(container).width();
	_gv.slideHeight = _gv.slideWidth*1 / 2;
    _gv.swipeWrap.style.width = (_gv.slideCount * _gv.slideWidth) + 'px';
	// 高宽处理
	if(_opts.width && _opts.fixWidth){
		container.style.width = _opts.width+"px";
		_gv.slideWidth = _opts.width;
	}
	if(_opts.height && _opts.fixHeight){
		container.style.height = _opts.height+"px";
		_gv.slideHeight = _opts.height;
        _gv.swipeWrap.style.height = _opts.height;
        container.style.height = _opts.height;
	}
	var pos = _gv.slideCount;
    while(pos--) {
      var slide = _gv.slideEles[pos];
      slide.style.width = _gv.slideWidth + 'px';// 设置滑动块高宽
	  slide.children[0].style.width = _gv.slideWidth + 'px';// 设置图片高宽
      if(_opts.fixHeight){
          slide.style.height = _gv.slideHeight + "px";
          slide.children[0].style.height = _gv.slideHeight + "px";
      }
      slide.setAttribute('data-index', pos);
      if(!_opts.dotsElement && $(slide).find(".dots").length == 0){
		  var dotsHtml = createDotHtml(pos);
		  if(dotsHtml){slide.appendChild(dotsHtml);}
      }
      if (browser.transitions) {
        slide.style.left = (pos * -_gv.slideWidth) + 'px';
        move(pos, _gv.index > pos ? -_gv.slideWidth : (_gv.index < pos ? _gv.slideWidth : 0), 0);
      }
    }
    // reposition elements before and after index
    if (_opts.continuous && browser.transitions) {
      move(circle(_gv.index-1), -_gv.slideWidth, 0);
      move(circle(_gv.index+1), _gv.slideWidth, 0);
    }
    if (!browser.transitions) _gv.swipeWrap.style.left = (_gv.index * -_gv.slideWidth) + 'px';
    container.style.visibility = 'visible';

    // 兼容客户端图片放大
    if(!window.swipeImgs){
       window.swipeImgs = "";
       $(_gv.swipeWrap).find("img").each(function(){
              window.swipeImgs += fullctx+$(this).attr("lazysrc")+";";
       });
       window.swipeImgs = window.swipeImgs.replace(/;$/,"");
    }

	// 显示原图 S
	if(_opts.showOrgImg && $("#original-img-div").length == 0){
		// 创建原图显示元素
		var html = ['<div id="original-img-div" style="display:none;width:100%;max-width:800px;position:fixed;top:0px;left:0px;background:#000;z-index: 1;">'];
		html[html.length] = '<div style="display:table;height:100%;width:100%;">';
		html[html.length] = '<div id="prev-img-div" style="width:100%;vertical-align:middle;display:table-cell;">';
        html[html.length] = '<img id="prev-img" src="'+ctx+'/site/images/default.jpg" style="width:100%;">';
        html[html.length] = '</div>';
        html[html.length] = '</div>';
		html[html.length] = '</div>';
		$("body").append(html.join(""));
		_gv.hammer = Hammer(document.getElementById('prev-img-div'), {
			transform_always_block: true,
			transform_min_scale: 1,
			drag_block_horizontal: true,
			drag_block_vertical: true,
			drag_min_distance: 10
		});
		_gv.prevImg =  document.getElementById('prev-img');
		_gv.posX=0;_gv.posY=0;_gv.scale=1;_gv.last_scale;_gv.rotation= 0;_gv.last_rotation;_gv.lastX=0;_gv.lastY=0;
		_gv.hammer.on('click touch tap drag transform', function(ev) {
			switch(ev.type) {
				case 'touch':
					_gv.last_scale = _gv.scale;
					_gv.last_rotation = _gv.rotation;
					_gv.lastY = _gv.posY;
					_gv.lastX = _gv.posX;
					break;
				case 'click':
					$("#original-img-div").hide();
					break;
				case 'drag':
					_gv.posX = _gv.lastX + ev.gesture.deltaX;
					_gv.posY = _gv.lastY + ev.gesture.deltaY;
					break;
				case 'transform':
					_gv.rotation = _gv.last_rotation + ev.gesture.rotation;
					_gv.scale = Math.max(1, Math.min(_gv.last_scale * ev.gesture.scale, 10));
					break;
			}
			ev.preventDefault();
			var transform =  "rotate(0deg) ";
			if(Math.abs(_gv.posX) > 30 || Math.abs(_gv.posY) > 30){
				transform = "translate3d("+_gv.posX+"px,"+_gv.posY+"px, 0) ";
			}
			transform += "scale3d("+_gv.scale+","+_gv.scale+", 0) ";
			_gv.prevImg.style.transform = transform;
			_gv.prevImg.style.oTransform = transform;
			_gv.prevImg.style.msTransform = transform;
			_gv.prevImg.style.mozTransform = transform;
			_gv.prevImg.style.webkitTransform = transform;
		});
		// 绑定点击事件
		$(_gv.swipeWrap).delegate("img","click",function(){
            $("#prev-img").attr("src", ctx+$(this).attr("lazysrc"));
            $("#original-img-div").css("left",$("body").width() >800 ? ($("body").width() - 800)/2 : 0).height($(window).height());
            $("#original-img-div").show();
        });
		$(window).on("resize",function(){
            $("#original-img-div").height($(window).height());
        });
	}
	// 显示原图 E
  }

  /*** 创建小圆点HTML元素对象 ***/
  function createDotHtml(n){
      var length = _gv.slideCount;
      if (length < 2) return null;
      var html = [];
      for(var i=0;i<length;i++){
          if(n == i){
              html[i] = '<b class="select"></b>'
          }else{
              html[i] = "<b></b>";
          }
      }

      var dotsElement = document.createElement("span");
      dotsElement.className = "dots";
      dotsElement.innerHTML = html.join("");
      return dotsElement;
  }

  // 生成小圆点
  function createDots(n){
      if(_gv.dotsElement) return;
      var length = _gv.slideCount;
      if (length < 2) return;
      var html = ['<b class="select"></b>'];
      length--;
      while(length--) {
          html[html.length] = "<b></b>";
      }
	  _gv.dotsElement = document.createElement("span");
	  _gv.dotsElement.className = "dots";
	  _gv.dotsElement.innerHTML = html.join("");
      _gv.dotsElement.style.position = "static";
     if(typeof _opts.dotsElement == "string"){
        document.getElementById(_opts.dotsElement).appendChild(_gv.dotsElement);
     }else{
        _opts.dotsElement.appendChild(_gv.dotsElement);
     }
  }
  function prev() {
    slide(_gv.index-1);
  }
  function next() {
     slide(_gv.index+1);
  }
  function circle(pindex) {
    // a simple positive modulo using _gv.slideCount
    return (_gv.slideCount + (pindex % _gv.slideCount)) % _gv.slideCount;
  }
  function slide(to, slideSpeed) {
    // do nothing if already on requested slide
    if (_gv.index == to) return;
    if (browser.transitions) {
      var direction = Math.abs(_gv.index-to) / (_gv.index-to); // 1: backward, -1: forward
      // get the actual position of the slide
      if (_opts.continuous) {
        var natural_direction = direction;
        direction = -_gv.slidePos[circle(to)] / _gv.slideWidth;
        if (direction !== natural_direction) to =  -direction * _gv.slideCount + to;
      }
      var diff = Math.abs(_gv.index-to) - 1;
      // move all the slideEles between index and to in the right direction
      while (diff--) move( circle((to > _gv.index ? to : _gv.index) - diff - 1), _gv.slideWidth * direction, 0);

      to = circle(to);
      move(_gv.index, _gv.slideWidth * direction, slideSpeed || _opts.speed);
      move(to, 0, slideSpeed || _opts.speed);

      if(_opts.continuous){
          if(_gv.slideCount == 2){
              move(circle(to+1), _gv.slideWidth * direction, slideSpeed || _opts.speed);
              _gv.timeout = setTimeout(function(){
                  move(circle(to+1), _gv.slideWidth * direction*-1, 0);
                  clearTimeout(_gv.timeout);
              },slideSpeed || _opts.speed);
          }else{
              move(circle(to - direction), -(_gv.slideWidth * direction),0);
          }
      }

    } else {
      to = circle(to);
	  if(to*1 < _gv.index*1){
		 animate(_gv.index * -_gv.slideWidth, to * -_gv.slideWidth, 1);
	  }else{
		 animate(_gv.index * -_gv.slideWidth, to * -_gv.slideWidth, slideSpeed || _opts.speed);
	  }
    }
    _gv.index = to;
	// 滑动结束事件处理
	if(typeof _opts.slideEnd == "function"){
		_opts.slideEnd.apply(this,[_gv.index, _gv.slideCount,_gv.slideEles[_gv.index]]);
	}
    changeSelectDot();
  }

   // 修改选中项
  function changeSelectDot(){
	if(!_gv.dotsElement || !_opts.dotsElement){return;}
	var dots = _gv.dotsElement.children;
	for(var i=0,len=dots.length;i<len;i++){
		dots[i].className = "";
	}
	dots[_gv.index].className = "select";
  }

  function move(pindex, dist, slideSpeed) {
    translate(pindex, dist, slideSpeed);
    _gv.slidePos[pindex] = dist;
  }

  function translate(pindex, dist, slideSpeed) {
    var slide = _gv.slideEles[pindex];
    var style = slide && slide.style;
    if (!style) return;
    style.webkitTransitionDuration =
    style.MozTransitionDuration = 
    style.msTransitionDuration = 
    style.OTransitionDuration =
    style.transitionDuration = slideSpeed + 'ms';
    style.webkitTransform = 'translate(' + dist + 'px,0)' + 'translateZ(0)';
    style.msTransform = 
    style.MozTransform = 
    style.OTransform = 'translateX(' + dist + 'px)';
  }
  function animate(from, to, slideSpeed) {
    // if not an animation, just reposition
    if (!slideSpeed) {
      _gv.swipeWrap.style.left = to + 'px';
      return;
    }
    var start = +new Date;
    var timer = setInterval(function() {
      var timeElap = +new Date - start;
      if (timeElap > slideSpeed) {
        _gv.swipeWrap.style.left = to + 'px';
        if (_opts.auto) begin();
        // 滑动结束事件处理
		if(typeof _opts.slideEnd == "function"){
			_opts.slideEnd.apply(this,[_gv.index, _gv.slideCount, _gv.slideEles[_gv.index]]);
		}
        clearInterval(timer);
        return;
      }
      _gv.swipeWrap.style.left = (( (to - from) * (Math.floor((timeElap / slideSpeed) * 100) / 100) ) + from) + 'px';
    }, 4);
  }

  // setup auto slideshow
  function begin() {
    _gv.slideInterval = setTimeout(next, _opts.delay);
  }
  function stop() {
    //_opts.delay = 0;
    clearTimeout(_gv.slideInterval);
  }
  // setup initial vars
     
  // setup event capturing
  var events = {
    handleEvent: function(event) {
      switch (event.type) {
        case 'touchstart': this.start(event); break;
        case 'touchmove': this.move(event); break;
        case 'touchend': offloadFn(this.end(event)); break;
        case 'webkitTransitionEnd':
        case 'msTransitionEnd':
        case 'oTransitionEnd':
        case 'otransitionend':
        case 'transitionend': offloadFn(this.transitionEnd(event)); break;
        case 'resize': offloadFn(setup.call()); break;
      }
      if (_opts.stopPropagation) event.stopPropagation();
    },
    start: function(event) {
      var touches = event.touches[0];
      // measure start values
      _gv.evtStart = {
        // get initial touch coords
        x: touches.pageX,
        y: touches.pageY,
        // store time to determine touch duration
        time: (new Date()).getTime()
      };
      // used for testing first move event
      _gv.isScrolling = undefined;
      // reset delta and end measurements
      _gv.evtDelta = {};
      // attach touchmove and touchend listeners
      _gv.swipeWrap.addEventListener('touchmove', this, false);
      _gv.swipeWrap.addEventListener('touchend', this, false);
    },
    move: function(event) {
      // ensure swiping with one touch and not pinching
      if ( event.touches.length > 1 || event.scale && event.scale !== 1) return
      if (_opts.disableScroll) event.preventDefault();
      var touches = event.touches[0];
      // measure change in x and y
      _gv.evtDelta = {
        x: touches.pageX - _gv.evtStart.x,
        y: touches.pageY - _gv.evtStart.y
      }
      // determine if scrolling test has run - one time test
      if ( typeof _gv.isScrolling == 'undefined') {
        _gv.isScrolling = !!( _gv.isScrolling || Math.abs(_gv.evtDelta.x) < Math.abs(_gv.evtDelta.y) );
      }
      // if user is not trying to scroll vertically
      if (!_gv.isScrolling) {
        // prevent native scrolling 
        event.preventDefault();
        // stop slideshow
        stop();
        // increase resistance if first or last slide
        if (_opts.continuous) { // we don't add resistance at the end
          translate(circle(_gv.index-1), _gv.evtDelta.x + _gv.slidePos[circle(_gv.index-1)], 0);
          translate(_gv.index, _gv.evtDelta.x + _gv.slidePos[_gv.index], 0);
          translate(circle(_gv.index+1), _gv.evtDelta.x + _gv.slidePos[circle(_gv.index+1)], 0);
        } else {
          _gv.evtDelta.x = 
            _gv.evtDelta.x / 
              ( (!_gv.index && _gv.evtDelta.x > 0               // if first slide and sliding left
                || _gv.index == _gv.slideCount - 1        // or if last slide and sliding right
                && _gv.evtDelta.x < 0                       // and if sliding at all
              ) ?                      
              ( Math.abs(_gv.evtDelta.x) / _gv.slideWidth + 1 )      // determine resistance level
              : 1 );                                 // no resistance if false
          // translate 1:1
          translate(_gv.index-1, _gv.evtDelta.x + _gv.slidePos[_gv.index-1], 0);
          translate(_gv.index, _gv.evtDelta.x + _gv.slidePos[_gv.index], 0);
          translate(_gv.index+1, _gv.evtDelta.x + _gv.slidePos[_gv.index+1], 0);
        }
      }
    },
    end: function(event) {
      // measure duration
      var duration = (new Date()).getTime() - _gv.evtStart.time;
        var isValidSlide = Number(duration) < 250               // if slide duration is less than 250ms
        && Math.abs(_gv.evtDelta.x) > 10            // and if slide amt is greater than 20px
        || Math.abs(_gv.evtDelta.x) > 10;      // or if slide amt is greater than half the width
      // determine if slide attempt is past start and end
      var isPastBounds = !_gv.index && _gv.evtDelta.x > 0                            // if first slide and slide amt is greater than 0
            || _gv.index == _gv.slideCount - 1 && _gv.evtDelta.x < 0;    // or if last slide and slide amt is less than 0
      if (_opts.continuous) isPastBounds = false;
      // if not scrolling vertically
      if (!_gv.isScrolling) {
        if (isValidSlide && !isPastBounds) {
			_gv.evtDelta.x < 0 ? slide(_gv.index+1,10) :  slide(_gv.index-1,10);
		  // 改变选中标识项
          changeSelectDot();
          // 滑动结束事件处理
		  if(typeof _opts.slideEnd == "function"){
			 _opts.slideEnd.apply(this,[_gv.index, _gv.slideCount, _gv.slideEles[_gv.index]]);
		  }
        } else {
          if (_opts.continuous) {
            move(circle(_gv.index-1), -_gv.slideWidth, _opts.speed);
            move(_gv.index, 0, _opts.speed);
            move(circle(_gv.index+1), _gv.slideWidth, _opts.speed);
          } else {
            move(_gv.index-1, -_gv.slideWidth, _opts.speed);
            move(_gv.index, 0, _opts.speed);
            move(_gv.index+1, _gv.slideWidth, _opts.speed);
          }
        }
      }
      // kill touchmove and touchend event listeners until touchstart called again
      _gv.swipeWrap.removeEventListener('touchmove', events, false)
      _gv.swipeWrap.removeEventListener('touchend', events, false)
    },
    transitionEnd: function(event) {
      if (parseInt(event.target.getAttribute('data-index')) == _gv.index) {
        if (_opts.auto) begin();
        // 滑动结束事件处理
		if(typeof _opts.slideEnd == "function"){
			_opts.slideEnd.apply(this,[_gv.index, _gv.slideCount,_gv.slideEles[_gv.index]]);
		}
      }
    }
  }
  // trigger setup
  setup();
  // start auto slideshow if applicable
  if(_opts.auto){
	  begin();
  };
  // add event listeners
  if (browser.addEventListener) {
    // set touchstart event on element    
    if (browser.touch) _gv.swipeWrap.addEventListener('touchstart', events, false);
    if (browser.transitions) {
      _gv.swipeWrap.addEventListener('webkitTransitionEnd', events, false);
      _gv.swipeWrap.addEventListener('msTransitionEnd', events, false);
      _gv.swipeWrap.addEventListener('oTransitionEnd', events, false);
      _gv.swipeWrap.addEventListener('otransitionend', events, false);
      _gv.swipeWrap.addEventListener('transitionend', events, false);
    }
    // set resize event on window
    window.addEventListener('resize', events, false);
  } else {
    window.onresize = function () { setup() }; // to play nice with old IE
  }
  // expose the Swipe API
  return {
    setup: function() {
      setup();
    },
    slide: function(to, slideSpeed) {
	  // cancel slideshow
      stop();
      slide(to, slideSpeed);
    },
    prev: function() {
      // cancel slideshow
      stop();
      prev();
    },
    next: function() {
      // cancel slideshow
      stop();
      next();
    },
    getPos: function() {
      // return current index position
      return _gv.index;
    },
    getNumSlides: function() {
      
      // return total number of slides
      return _gv.slideCount;
    },
    kill: function() {
      // cancel slideshow
      stop();
      // reset element
      _gv.swipeWrap.style.width = 'auto';
      _gv.swipeWrap.style.left = 0;
      // reset slideEles
      var pos = _gv.slideCount;
      while(pos--) {
        var slide = _gv.slideEles[pos];
        slide.style.width = '100%';
        slide.style.left = 0;
        if (browser.transitions) translate(pos, 0, 0);
      }
      // removed event listeners
      if (browser.addEventListener) {
        // remove current event listeners
        _gv.swipeWrap.removeEventListener('touchstart', events, false);
        _gv.swipeWrap.removeEventListener('webkitTransitionEnd', events, false);
        _gv.swipeWrap.removeEventListener('msTransitionEnd', events, false);
        _gv.swipeWrap.removeEventListener('oTransitionEnd', events, false);
        _gv.swipeWrap.removeEventListener('otransitionend', events, false);
        _gv.swipeWrap.removeEventListener('transitionend', events, false);
        window.removeEventListener('resize', events, false);
      }else {
        window.onresize = null;
      }
    }
  }
}
if ( window.jQuery || window.Zepto ) {
  (function($) {
    $.fn.Swipe = function(params) {
      return this.each(function() {
        $(this).data('Swipe', new Swipe($(this)[0], params));
      });
    }
  })( window.jQuery || window.Zepto )
}